#include <autoconfig.h>
#include <linux/types.h>
#include <linux/spi/spidev.h>
#include <sys/ioctl.h>

#include <assert.h>
#include <string.h>
#include <stdint.h>
#include <stdbool.h>
#include <unistd.h>
#include <stdlib.h>
#include <getopt.h>
#include <fcntl.h>
#include <stdio.h>

#include "proginfo.h"
// #include "fpga-tr700.h"
#include "printl.h"

#include "pthread.h"
// #include "fpga-otdr-cfg.h"
// #include "fpga_encode.h"

#include "port.h"
#include "fpga-common.h"
// #include "./protocal-otdr.h"
#include "fpga-private.h"
#include "port.h"
#include "interface/protocal-ocid.h"


// #include "fpga-common.h"
// #include "protocal-otdr.h"

// #include "encode-otdr.h"


// Fix LS2K unsupport cs unchange
#define CONFIG_READ_1000_POINT (0)

#define SPI_TP_BEGIN           _IOR(SPI_IOC_MAGIC, 5, __u8)
#define SPI_TP_COMMIT          _IOR(SPI_IOC_MAGIC, 6, __u8)

// #define this_dbg(fmt, ...) \
// 	PRINTL(OTDR_DBG_LEVEL, C_DEBUG fmt C_NORMAL, ##__VA_ARGS__)

#define this_dbg(fmt, ...)

#if defined(CONFIG_USE_DEBUG_ENV)
#define ENV_PRINT_E(fmt, ...)                              \
    if (env_print_e) {                                     \
	_ctstprint(C_ERROR, C_NORMAL, fmt, ##__VA_ARGS__); \
    }
#define ENV_PRINT_W(fmt, ...)                             \
    if (env_print_w) {                                    \
	_ctstprint(C_WARN, C_NORMAL, fmt, ##__VA_ARGS__); \
    }
#else
#define ENV_PRINT_E(fmt, ...)
#define ENV_PRINT_w(fmt, ...)
#endif


struct _fpga_ocid_param_tx
{
    char  ch;
    short post;  // 位置（由FPGA自己决定起始、结束位置）
} __attribute__((__packed__));


#define RETRY (3)
// int cp_fpga_ocid_sensitive(struct fpga_dev *dev, int sensitive);
int cp_fpga_ocid_param(struct fpga_dev *dev, struct fpga_ocid_test_param *val)
{


    // ENV_PRINT_W("未实现");
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    struct _fpga_ocid_param_tx tbuf;

    // TODO 改成fpga_send_data

    tbuf.ch   = val->ch & 0xff;
    tbuf.post = val->post;


    // 	// ENV_PRINT_W("Encode:\r\n");
    // 	// ENV_PRINT_W("    ch             %4.4x\n", tbuf.ch);
    // 	// ENV_PRINT_W("    post             %4.4x\n", tbuf.post);

    dev->ch = tbuf.ch;

    char          rbuf[MIN_RX_PACK_SIZE];
    unsigned char ack;

    for (int retry = 0; retry < RETRY; retry++) {
	_fpga_transfer(dev, OCID_PARAM, (char *)&tbuf, sizeof(struct _fpga_ocid_param_tx), rbuf, ARRAY_SIZE(rbuf));
	ack = ACK_CODE(rbuf);
	switch (ack) {
	case 0xaa:
	    this_dbg("%s() OK\r\n", __FUNCTION__);
	    // usleep(10000);// FPGA控制光耦
	    goto _End;
	case 0x55:
	    ENV_PRINT_W("Error\r\n");
	    return -1;
	default:
	    ENV_PRINT_E("unknow\r\n");
	    return -1;
	}
    }
    return -1;
_End:
    return cp_fpga_ocid_sensitive(dev, val->sensitive);
}
int cp_fpga_ocid_sensitive(struct fpga_dev *dev, int sensitive)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    // TODO 改成fpga_send_data
    char tbuf[3];
    char rbuf[MIN_RX_PACK_SIZE];


    tbuf[0] = dev->ch;
    tbuf[1] = sensitive & 0xff;
    tbuf[2] = (sensitive >> 8) & 0xff;
    // ENV_PRINT_W("发送3个字节，FPGA是否正确接收???\r\n");
    // ENV_PRINT_W("先发通道 %x 后发电平 [%x %x]\r\n", tbuf[0], tbuf[1], tbuf[2]);
    mutex_unlock(&dev->mutex);
    _fpga_transfer(dev, OCID_LEVEL, tbuf, ARRAY_SIZE(tbuf), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
    return -1;
}
int cp_ocid_set_gpio(struct fpga_dev *dev, int io, int val)
{
    if (io == IO_OCID_SENSITIVE) {
	return cp_fpga_ocid_sensitive(dev, val);
    }
    return 0;
}


// /*
//   里面的数据是小端顺序
//   以字节方式打印  aa bb cc 23
//   小端4字节对齐后 23 cc bb aa
//   去掉标志        00 cc bb aa
// */
void _ocid_clear_flag(unsigned char *data, unsigned long len)
{
    unsigned long *p32 = (unsigned long *)data;
    for (int i = 0; i < len; i++) {
	*p32 = *p32 & 0x00ffffff;
	p32++;
    }
}
int cp_fpga_read_ocid_data(
	struct fpga_dev *dev,
	unsigned char   *ocid_data,
	unsigned long    len,
	unsigned long   *rlen)
{
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    // TODO 改成fpga_send_data
    char rbuf[MIN_RX_PACK_SIZE];
    // 验证传入的内存不是非法
    bzero(ocid_data, sizeof(unsigned int) * len);
    this_dbg("%s() \r\n", __FUNCTION__);

    mutex_unlock(&dev->mutex);
    _fpga_transfer(dev, OCID_READ_DATA, &dev->ch, sizeof(dev->ch), ocid_data, sizeof(unsigned int) * len);
    mutex_unlock(&dev->mutex);

    _ocid_clear_flag(ocid_data, len);
    *rlen = len;
    return 0;
}

int cp_fpga_ocid_start(struct fpga_dev *dev)
{
    // TODO 改成fpga_send_data
    // 	// ENV_PRINT_W("未实现");

    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    char rbuf[MIN_RX_PACK_SIZE];

    mutex_unlock(&dev->mutex);
    _fpga_transfer(dev, OCID_START, &dev->ch, sizeof(dev->ch), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
    return -1;
}
int cp_fpga_ocid_stop(struct fpga_dev *dev)
{
    // 	// ENV_PRINT_W("未实现");
    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    // TODO 改成fpga_send_data
    char rbuf[MIN_RX_PACK_SIZE];

    mutex_lock(&dev->mutex);
    _fpga_transfer(dev, OTDR_STOP, &dev->ch, sizeof(dev->ch), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);
    switch (ack) {
    case 0xaa:
	this_dbg("%s() OK\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	ENV_PRINT_W("Error\r\n");
	return -1;
    default:
	ENV_PRINT_E("unknow\r\n");
	return -1;
    }
    return -1;
}


int cb_fpga_ocid_probe(struct fpga_dev *dev)
{
    return 0;
}
int cb_fpga_ocid_release(struct fpga_dev *dev)
{
    return 0;
}


int cb_fpga_alarm(struct fpga_dev *dev, int ch, int is_appear)
{
    // OTDR_ALARM_APPEAR
    // printf("作废%s() 用fpga_gpio()代替\r\n", __FUNCTION__);

    assert(dev != NULL);
    assert(dev->desc == dev_desc);

    char tbuf[2];
    char rbuf[MIN_RX_PACK_SIZE];
    int  cmd = OTDR_ALARM_APPEAR;

    if (is_appear != 1) {
	cmd = OTDR_ALARM_DISAPPEAR;
    }

    tbuf[0] = ch;
    tbuf[1] = 0;  // 无用

    mutex_lock(&dev->mutex);
    _fpga_transfer(dev, cmd, tbuf, ARRAY_SIZE(tbuf), rbuf, ARRAY_SIZE(rbuf));
    mutex_unlock(&dev->mutex);

    unsigned char ack = ACK_CODE(rbuf);

    switch (ack) {
    case 0xaa:
	printf("%s() exist\r\n", __FUNCTION__);
	return 0;
    case 0x55:
	printf("%s() free\r\n", __FUNCTION__);
	return -1;
    default:
	// ENV_PRINT_E("unknow\r\n");
	return -1;
    }

    return 0;
}
